<template>
  <div
    ref="handleRef"
    class="resize-handle"
    :class="handleClasses"
    :style="handleStyles"
    @mousedown="handleMouseDown"
  >
    <!-- 延迟模式下的虚影效果 -->
    <div
      v-if="props.responseMode === 'delayed' && isDragging && showPreview"
      class="resize-preview"
      :class="previewClasses"
      :style="previewPositionStyle"
    />
    <v-icon
      v-if="showIcon"
      color="grey"
      data-testid="resize-marginLeft-mdiDotsVertical"
      :icon="mdiDotsVertical"
      :size="18"
      :style="{ marginLeft: -((9 - handleSize) / 2) + 'px' }"
    ></v-icon>
  </div>
</template>

<script setup lang="ts">
import { mdiDotsVertical } from '@mdi/js'
interface Props {
  direction: 'left' | 'right' | 'top' | 'bottom'
  minSize?: number
  maxSize?: number
  responseMode?: 'delayed' | 'realtime'
  handleSize?: number
  showIcon?: boolean
  offset?: number
}

const props = withDefaults(defineProps<Props>(), {
  minSize: 50,
  maxSize: 1500,
  responseMode: 'realtime',
  handleSize: 8,
  showIcon: false,
  offset: 0
})

// 使用 defineModel 实现双向绑定
const modelValue = defineModel<number>({ required: true })

// 组件引用
const handleRef = ref<HTMLElement>()

// 拖拽状态
const isDragging = ref(false)
const startPosition = ref({ x: 0, y: 0 })
const startSize = ref(0)
const previewSize = ref(0)
const showPreview = ref(false)
const currentDelta = ref(0)
const previewOffset = ref(0)

// 计算属性：处理器样式类
const handleClasses = computed(() => ({
  'resize-handle--horizontal': props.direction === 'left' || props.direction === 'right',
  'resize-handle--vertical': props.direction === 'top' || props.direction === 'bottom',
  'resize-handle--left': props.direction === 'left',
  'resize-handle--right': props.direction === 'right',
  'resize-handle--top': props.direction === 'top',
  'resize-handle--bottom': props.direction === 'bottom',
  'resize-handle--dragging': isDragging.value,
  'resize-handle--delayed': props.responseMode === 'delayed'
}))

// 计算属性：虚影样式类
const previewClasses = computed(() => ({
  'resize-preview--horizontal': props.direction === 'left' || props.direction === 'right',
  'resize-preview--vertical': props.direction === 'top' || props.direction === 'bottom',
  'resize-preview--left': props.direction === 'left',
  'resize-preview--right': props.direction === 'right',
  'resize-preview--top': props.direction === 'top',
  'resize-preview--bottom': props.direction === 'bottom'
}))

// 计算属性：处理器样式
const handleStyles = computed(() => {
  const isHorizontal = props.direction === 'left' || props.direction === 'right'
  const size = `${props.handleSize}px`

  return {
    cursor: isHorizontal ? 'ew-resize' : 'ns-resize',
    position: 'absolute' as const,
    zIndex: 10,
    ...(isHorizontal
      ? {
          width: size,
          height: '100%',
          top: '0',
          [props.direction]: `${props.offset}px`
        }
      : {
          width: '100%',
          height: size,
          left: '0',
          [props.direction]: `${props.offset}px`
        })
  }
})

// 计算属性：虚影位置样式（基于实际拖拽距离）
// 起始时对齐鼠标位置，此后保持与鼠标的相对距离不变
const previewPositionStyle = computed(() => {
  const offset = previewOffset.value
  switch (props.direction) {
    case 'right': {
      return { left: `${offset + currentDelta.value}px` }
    }
    case 'left': {
      return { right: `${offset + currentDelta.value}px` }
    }
    case 'bottom': {
      return { top: `${offset + currentDelta.value}px` }
    }
    case 'top': {
      return { bottom: `${offset + currentDelta.value}px` }
    }
    default: {
      return {}
    }
  }
})

// 鼠标按下事件处理
function handleMouseDown(event: MouseEvent) {
  event.preventDefault()
  event.stopPropagation()

  isDragging.value = true
  // 使用 screenX/screenY 避免窗口尺寸变化时的坐标抖动
  startPosition.value = { x: event.screenX, y: event.screenY }
  startSize.value = modelValue.value
  previewSize.value = modelValue.value
  currentDelta.value = 0

  // 记录鼠标在手柄内的相对位置，使虚影起始时就与光标对齐
  const handleEl = handleRef.value
  if (handleEl) {
    const rect = handleEl.getBoundingClientRect()
    const clientX = event.clientX ?? event.screenX
    const clientY = event.clientY ?? event.screenY

    if (props.direction === 'left' || props.direction === 'right') {
      previewOffset.value = props.direction === 'right' ? clientX - rect.left : rect.right - clientX
    } else {
      previewOffset.value =
        props.direction === 'bottom' ? clientY - rect.top : rect.bottom - clientY
    }
  } else {
    previewOffset.value = 0
  }

  showPreview.value = props.responseMode === 'delayed'

  // 添加全局事件监听
  document.addEventListener('mousemove', handleMouseMove)
  document.addEventListener('mouseup', handleMouseUp)

  // 防止文本选择
  document.body.style.userSelect = 'none'
  document.body.style.cursor = handleStyles.value.cursor as string
}

// 鼠标移动事件处理
function handleMouseMove(event: MouseEvent) {
  if (!isDragging.value) return

  // 使用 screenX/screenY 计算偏移量，避免窗口尺寸变化时的坐标抖动
  const deltaX = event.screenX - startPosition.value.x
  const deltaY = event.screenY - startPosition.value.y

  // 始终基于初始尺寸和鼠标偏移量计算新尺寸，避免累积误差
  let newSize: number

  switch (props.direction) {
    case 'right': {
      // 向右拖拽：初始尺寸 + 水平偏移量
      newSize = startSize.value + deltaX
      break
    }
    case 'left': {
      // 向左拖拽：初始尺寸 - 水平偏移量（向左移动减少尺寸）
      newSize = startSize.value - deltaX
      break
    }
    case 'bottom': {
      // 向下拖拽：初始尺寸 + 垂直偏移量
      newSize = startSize.value + deltaY
      break
    }
    case 'top': {
      // 向上拖拽：初始尺寸 - 垂直偏移量（向上移动减少尺寸）
      newSize = startSize.value - deltaY
      break
    }
    default: {
      newSize = startSize.value
    }
  }

  // 应用尺寸限制，确保在允许范围内
  const constrainedSize = Math.max(props.minSize, Math.min(props.maxSize, newSize))

  if (props.responseMode === 'realtime') {
    // 实时模式：直接更新 model 值，无条件判断确保流畅性
    // 移除 !== 判断，因为即使值相同也要确保响应性
    modelValue.value = constrainedSize
  } else {
    // 延迟模式：更新预览尺寸和虚影位置
    previewSize.value = constrainedSize

    // 虚影位置基于原始鼠标移动距离，提供流畅的视觉反馈
    switch (props.direction) {
      case 'right': {
        currentDelta.value = deltaX
        break
      }
      case 'left': {
        currentDelta.value = -deltaX
        break
      }
      case 'bottom': {
        currentDelta.value = deltaY
        break
      }
      case 'top': {
        currentDelta.value = -deltaY
        break
      }
    }
  }
}

// 鼠标释放事件处理
function handleMouseUp() {
  if (!isDragging.value) return

  // 延迟模式：在鼠标释放时更新 model 值
  if (props.responseMode === 'delayed' && previewSize.value !== modelValue.value) {
    modelValue.value = previewSize.value
  }

  isDragging.value = false
  showPreview.value = false
  currentDelta.value = 0

  // 移除全局事件监听
  document.removeEventListener('mousemove', handleMouseMove)
  document.removeEventListener('mouseup', handleMouseUp)

  // 恢复默认样式
  document.body.style.userSelect = ''
  document.body.style.cursor = ''
}

// 监听 model 值变化，同步预览尺寸
watch(modelValue, newValue => {
  if (!isDragging.value) {
    previewSize.value = newValue
  }
})

// 组件卸载时清理事件监听
onUnmounted(() => {
  document.removeEventListener('mousemove', handleMouseMove)
  document.removeEventListener('mouseup', handleMouseUp)
  document.body.style.userSelect = ''
  document.body.style.cursor = ''
})
</script>

<style scoped lang="sass">
.resize-handle
  transition: background-color 0.2s ease
  position: relative
  display: flex
  align-items: center
  justify-content: center
  border-radius: 4px
  background: rgba(var(--v-theme-tab-active),0)
  &:hover
    background: rgba(var(--v-theme-warning),.2)
  &:active
    background: rgba(var(--v-theme-warning),.4)

  // 延迟模式下的特殊样式
  &--delayed
    &.resize-handle--dragging
      background: rgba(var(--v-theme-tab-active),.5)


// 虚影预览效果
.resize-preview
  position: absolute
  pointer-events: none
  background-color: rgba(var(--v-theme-primary), 0.6)
  box-shadow: 0 0 8px rgba(var(--v-theme-primary), 0.4)
  z-index: 1001
  // 移除过渡效果以避免拖拽时的延迟
  // transition: all 0.1s ease-out

  // 水平方向虚影（左右拖拽）
  &--horizontal
    width: 2px
    height: 100%
    top: 0
    border-radius: 1px

  // 垂直方向虚影（上下拖拽）
  &--vertical
    width: 100%
    height: 2px
    left: 0
    border-radius: 1px

  // 具体方向的虚影位置（位置通过内联样式动态控制）
  // 注意：以下方向类的位置由 JavaScript 通过内联样式动态设置
  // &--left: 位置通过内联样式的 right 属性控制
  // &--right: 位置通过内联样式的 left 属性控制
  // &--top: 位置通过内联样式的 bottom 属性控制
  // &--bottom: 位置通过内联样式的 top 属性控制

  // 虚影动画效果
  &:before
    content: ''
    position: absolute
    top: -2px
    left: -2px
    right: -2px
    bottom: -2px
    background: rgba(var(--v-theme-primary), 0.2)
    border-radius: 3px

// 防止在拖拽时选择文本
.resize-handle--dragging
  *
    user-select: none !important
    pointer-events: none !important
</style>
